// Transform.cpp: implementation of the Transform class.


#include "Transform.h"
/*
#include "stdio.h"

void printMat(mat3 mat){
	printf("mat:\n[%.3f,%.3f,%.3f]\n[%.3f,%.3f,%.3f]\n[%.3f,%.3f,%.3f]\n",
				mat[0][0],mat[0][1],mat[0][2],
				mat[1][0],mat[1][1],mat[1][2],
				mat[2][0],mat[2][1],mat[2][2]);
}
void printMat(mat4 mat){
	printf("mat:\n[%.3f,%.3f,%.3f,%.3f]\n[%.3f,%.3f,%.3f,%.3f]\n[%.3f,%.3f,%.3f,%.3f]\n[%.3f,%.3f,%.3f,%.3f]\n",
				mat[0][0],mat[0][1],mat[0][2],mat[0][3],
				mat[1][0],mat[1][1],mat[1][2],mat[1][3],
				mat[2][0],mat[2][1],mat[2][2],mat[2][3],
				mat[3][0],mat[3][1],mat[3][2],mat[3][3]);
}
*/
// Helper rotation function.  Please implement this.  
mat3 Transform::rotate(const float degrees, const vec3& axis) {
  float costheta = glm::cos((degrees)*.0174532825f);
  float sintheta = glm::sin((degrees)*.0174532825f);
  mat3 matrix1(costheta);

  float x = axis[0];
  float y = axis[1];
  float z = axis[2];
  mat3 matrix2( x*x, x*y, x*z,
               x*y, y*y, y*z,
			   x*z, y*z, z*z);
  matrix2 *= (1-costheta);

  mat3 matrix3(0, -z, y,
			   z, 0, -x,
			  -y,x, 0);
  matrix3 *= sintheta;
  return matrix1+matrix2+matrix3;
}

void Transform::left(float degrees, vec3& eye, vec3& up) {
	//printf("left:%f\n",degrees);
	mat3 rotmat = Transform::rotate(-degrees, glm::normalize(up));
	eye = rotmat*eye;
}

void Transform::up(float degrees, vec3& eye, vec3& up) {
	//printf("up:%f, eye:%.2f,%.2f,%.2f\n",degrees, eye[0],eye[1],eye[2]);
	vec3 side = glm::cross(eye, up);
	mat3 rotmat = Transform::rotate(-degrees, glm::normalize(side));
	//printMat(rotmat);
	eye = rotmat*eye;
	up = rotmat*up;
	//printf("after: eye:%.2f,%.2f,%.2f\n", eye[0],eye[1],eye[2]);
}

mat4 Transform::lookAt(const vec3 &eye, const vec3 &center, const vec3 &up) {
  vec3 vecw = glm::normalize(eye-center);
  vec3 vecu = glm::normalize(glm::cross(up, vecw));
  vec3 vecv = glm::cross(vecw, vecu);
  mat4 lookat(vecu[0], vecu[1], vecu[2], -glm::dot(vecu,eye),
              vecv[0], vecv[1], vecv[2], -glm::dot(vecv,eye),
              vecw[0], vecw[1], vecw[2], -glm::dot(vecw,eye),
              0,0,0,1);
	return lookat;
}

mat4 Transform::perspective(float fovy, float aspect, float zNear, float zFar)
{
	float theta = fovy/2.0f;
	float d = 1.0f/(glm::tan(theta*.0174532825f));
	float A = -(zFar+zNear)/(zFar-zNear);
	float B = -2.0f*(zFar*zNear)/(zFar-zNear);
	
	mat4 ret( d/aspect, 0, 0, 0,
			  0,d,0,0,
			  0,0,A,B,
			  0,0,-1.0,0);
	return ret;
}

mat4 Transform::scale(const float &sx, const float &sy, const float &sz) {
	mat4 ret( sx,0,0, 0,
			  0,sy,0, 0,
			  0,0,sz, 0,
			  0,0,0, 1);
	return ret;
}

mat4 Transform::translate(const float &tx, const float &ty, const float &tz) {
	mat4 ret( 1,0,0, tx,
			  0,1,0, ty,
			  0,0,1, tz,
			  0,0,0, 1);
	return ret;
}

// To normalize the up direction and construct a coordinate frame.  
// As discussed in the lecture.  May be relevant to create a properly 
// orthogonal and normalized up. 
// This function is provided as a helper, in case you want to use it. 
// Using this function (in readfile.cpp or display.cpp) is optional.  

vec3 Transform::upvector(const vec3 &up, const vec3 & zvec) {
  vec3 x = glm::cross(up,zvec) ; 
  vec3 y = glm::cross(zvec,x) ; 
  vec3 ret = glm::normalize(y) ; 
  return ret ; 
}


Transform::Transform()
{

}

Transform::~Transform()
{

}
